package top.zsc.cloud.common.dao;

import top.zsc.cloud.common.constants.ConstantsKey;
import org.apache.ibatis.mapping.MappedStatement;
import tk.mybatis.mapper.MapperException;
import tk.mybatis.mapper.annotation.Version;
import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.mapperhelper.EntityHelper;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.mapper.mapperhelper.SelectKeyHelper;
import tk.mybatis.mapper.mapperhelper.SqlHelper;
import tk.mybatis.mapper.provider.base.BaseInsertProvider;
import tk.mybatis.mapper.version.VersionException;

import java.util.Iterator;
import java.util.Set;

/***
 * @title:<h3> 通用mybatis动态sql扩展 <h3>
 * @author: Enzo
 * @date: 2019-1-14 22:14
 * @params
 * @return
 **/
public class MapperCustomProvider extends BaseInsertProvider {
    public MapperCustomProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }


    /***
     * @title:<h3> 业务新增，为空的数据不插入到数据库 ，切面自动注入删除标记、乐观锁、创建人、创建时间<h3>
     * @author: Enzo
     * @date: 2019-1-14 22:13
     * @params [ms]
     * @return java.lang.String
     **/
    public String insertService(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        Set<EntityColumn> columnList = EntityHelper.getColumns(entityClass);
        this.processKey(sql, entityClass, ms, columnList);
        sql.append(SqlHelper.insertIntoTable(entityClass, this.tableName(entityClass)));
        sql.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
        Iterator var5 = columnList.iterator();
        EntityColumn column;
        while (var5.hasNext()) {
            column = (EntityColumn) var5.next();
            if (column.isInsertable()) {
                if (column.isIdentity()) {
                    //sql.append(column.getColumn() + ",");
                } else {
                    sql.append(SqlHelper.getIfNotNull(column, column.getColumn() + ",", this.isNotEmpty()));
                }
            }
        }
        sql.append("</trim>");
        sql.append("<trim prefix=\"VALUES(\" suffix=\")\" suffixOverrides=\",\">");
        var5 = columnList.iterator();
        while (var5.hasNext()) {
            column = (EntityColumn) var5.next();
            if (column.isInsertable()) {
                if (column.isIdentity()) {
                    sql.append(SqlHelper.getIfCacheNotNull(column, column.getColumnHolder((String) null, "_cache", ",")));
                } else {
                    sql.append(SqlHelper.getIfNotNull(column, column.getColumnHolder((String) null, (String) null, ","), this.isNotEmpty()));
                }
                if (column.isIdentity()) {
                   // sql.append(SqlHelper.getIfCacheIsNull(column, column.getColumnHolder() + ","));
                }
            }
        }
        sql.append("</trim>");
        return sql.toString();
    }

    private void processKey(StringBuilder sql, Class<?> entityClass, MappedStatement ms, Set<EntityColumn> columnList) {
        Boolean hasIdentityKey = false;
        Iterator var6 = columnList.iterator();

        EntityColumn column;
        label34:
        do {
            while (true) {
                while (var6.hasNext()) {
                    column = (EntityColumn) var6.next();
                    if (column.isIdentity()) {
                        sql.append(SqlHelper.getBindCache(column));
                        if (hasIdentityKey) {
                            continue label34;
                        }

                        SelectKeyHelper.newSelectKeyMappedStatement(ms, column, entityClass, this.isBEFORE(), this.getIDENTITY(column));
                        hasIdentityKey = true;
                    } else if (column.getGenIdClass() != null) {
                        sql.append("<bind name=\"").append(column.getColumn()).append("GenIdBind\" value=\"@tk.mybatis.mapper.genid.GenIdUtil@genId(");
                        sql.append("_parameter").append(", '").append(column.getProperty()).append("'");
                        sql.append(", @").append(column.getGenIdClass().getCanonicalName()).append("@class");
                        sql.append(", '").append(this.tableName(entityClass)).append("'");
                        sql.append(", '").append(column.getColumn()).append("')");
                        sql.append("\"/>");
                    }
                }

                return;
            }
        } while (column.getGenerator() != null && column.getGenerator().equals("JDBC"));

        throw new MapperException(ms.getId() + "对应的实体类" + entityClass.getCanonicalName() + "中包含多个MySql的自动增长列,最多只能有一个!");
    }

    /***
     * @title:<h3> 业务修改，忽略空值更新，添加乐观锁，切面追加修改时间、修改人 <h3>
     * @author: Enzo
     * @date: 2019-1-14 22:17
     * @params [ms]
     * @return java.lang.String
     **/
    public String updateService(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.updateTable(entityClass, this.tableName(entityClass)));
        sql.append(updateSetColumns(entityClass, (String) null, true, this.isNotEmpty()));
        sql.append(SqlHelper.wherePKColumns(entityClass, true));
        Iterator columnList = EntityHelper.getColumns(entityClass).iterator();
        while (columnList.hasNext()) {
            EntityColumn column = (EntityColumn) columnList.next();
            if (ConstantsKey.Field.VERSION.equals(column.getProperty())) {
                String versionField = "#{" + column.getProperty() + "}";
                if (sql.indexOf(versionField) > -1) {
                    sql.replace(sql.indexOf(versionField), sql.indexOf(versionField) + versionField.length(), column.getColumn() + "+1");
                }

                sql.replace(sql.lastIndexOf("</where>"), sql.length(), " <if test='"+column.getProperty()+"!=null'> AND " + column.getColumn() + "=#{" + column.getProperty() + "}</if></where>");
            }
        }

        return sql.toString();
    }

    /***
     * @title:<h3> 逻辑删除 <h3>
     * @author: Enzo
     * @date: 2019-1-14 22:50
     * @params [ms]
     * @return java.lang.String
     **/
    public String remove(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        Iterator columnList = EntityHelper.getColumns(entityClass).iterator();
        while (columnList.hasNext()) {
            EntityColumn column = (EntityColumn) columnList.next();
            if (ConstantsKey.Field.DELETED.equals(column.getProperty())) {
                sql.append(SqlHelper.updateTable(entityClass, this.tableName(entityClass)));
                sql.append("<set>" + column.getColumn() + "=1</set>");
                sql.append(SqlHelper.whereAllIfColumns(entityClass, true));
                break;
            }
        }
        //如果无标记删除字段，则做真删
        if (sql.length() == 0) {
            if (this.getConfig().isSafeDelete()) {
                sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getColumns(entityClass)));
            }
            sql.append(SqlHelper.deleteFromTable(entityClass, this.tableName(entityClass)));
            sql.append(SqlHelper.whereAllIfColumns(entityClass, this.isNotEmpty(), true));
        }
        return sql.toString();
    }

    /***
     * @title:<h3>根据主键id进行逻辑删除  <h3>
     * @author: Enzo
     * @date: 2019-1-14 22:50
     * @params [ms]
     * @return java.lang.String
     **/
    public String removeByPk(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        Iterator columnList = EntityHelper.getColumns(entityClass).iterator();
        while (columnList.hasNext()) {
            EntityColumn column = (EntityColumn) columnList.next();
            if (ConstantsKey.Field.DELETED.equals(column.getProperty())) {
                sql.append(SqlHelper.updateTable(entityClass, this.tableName(entityClass)));
                sql.append("<set>" + column.getColumn() + "=1</set>");
                break;
            }
        }
        //如果无标记删除字段，则做真删
        if (sql.length() == 0) {
            if (this.getConfig().isSafeDelete()) {
                sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getColumns(entityClass)));
            }
            sql.append(SqlHelper.deleteFromTable(entityClass, this.tableName(entityClass)));
        }
        sql.append(SqlHelper.wherePKColumns(entityClass, true));
        return sql.toString();
    }

    public String removeInPk(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        Iterator columnList = EntityHelper.getColumns(entityClass).iterator();
        while (columnList.hasNext()) {
            EntityColumn column = (EntityColumn) columnList.next();
            if (ConstantsKey.Field.DELETED.equals(column.getProperty())) {
                sql.append(SqlHelper.updateTable(entityClass, this.tableName(entityClass)));
                sql.append("<set>" + column.getColumn() + "=1</set>");
                break;
            }
        }
        //如果无标记删除字段，则做真删
        if (sql.length() == 0) {
            if (this.getConfig().isSafeDelete()) {
                sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getColumns(entityClass)));
            }
            sql.append(SqlHelper.deleteFromTable(entityClass, this.tableName(entityClass)));
        }
        Set<EntityColumn> columnSet = EntityHelper.getPKColumns(entityClass);
        Iterator var5 = columnSet.iterator();
        while (var5.hasNext()) {
            EntityColumn column2 = (EntityColumn) var5.next();
            sql.append("<where> AND " + column2.getColumn() + " in(${value})</where>");
        }
        return sql.toString();
    }

    public String removeInColumnFieldValue(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        Iterator columnList = EntityHelper.getColumns(entityClass).iterator();
        while (columnList.hasNext()) {
            EntityColumn column = (EntityColumn) columnList.next();
            if (ConstantsKey.Field.DELETED.equals(column.getProperty())) {
                sql.append(SqlHelper.updateTable(entityClass, this.tableName(entityClass)));
                sql.append("<set>" + column.getColumn() + "=1</set>");
                break;
            }
        }
        //如果无标记删除字段，则做真删
        if (sql.length() == 0) {
            if (this.getConfig().isSafeDelete()) {
                sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getColumns(entityClass)));
            }
            sql.append(SqlHelper.deleteFromTable(entityClass, this.tableName(entityClass)));
        }

        sql.append("<where> AND  ${column} in(${fieldValue})</where>");

        return sql.toString();
    }

    /***
     * @title:<h3> 根据条件删除 <h3>
     * @author: Enzo
     * @date: 2019-1-15 1:28
     * @params [ms]
     * @return java.lang.String
     **/
    public String removeByWhere(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        Iterator columnList = EntityHelper.getColumns(entityClass).iterator();
        while (columnList.hasNext()) {
            EntityColumn column = (EntityColumn) columnList.next();
            if (ConstantsKey.Field.DELETED.equals(column.getProperty())) {
                sql.append(SqlHelper.updateTable(entityClass, this.tableName(entityClass)));
                sql.append("<set>" + column.getColumn() + "=1</set>");
                break;
            }
        }
        //如果无标记删除字段，则做真删
        if (sql.length() == 0) {
            if (this.getConfig().isSafeDelete()) {
                sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getColumns(entityClass)));
            }
            sql.append(SqlHelper.deleteFromTable(entityClass, this.tableName(entityClass)));
        }
        sql.append("<where> AND  ${where}</where>");
        return sql.toString();
    }

    /***
     * @title:<h3> 查询所有未删除记录 <h3>
     * @author: Enzo
     * @date: 2019-1-14 23:02
     * @params [ms]
     * @return java.lang.String
     **/
    public String findAll(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        this.setResultType(ms, entityClass);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, this.tableName(entityClass)));
        Iterator columnList = EntityHelper.getColumns(entityClass).iterator();
        while (columnList.hasNext()) {
            EntityColumn column = (EntityColumn) columnList.next();
            if (ConstantsKey.Field.DELETED.equals(column.getProperty())) {
                sql.append("<where>" + column.getColumn() + "=0</where>");
                break;
            }
        }
        sql.append(SqlHelper.orderByDefault(entityClass));
        return sql.toString();
    }

    /***
     * @title:<h3> 根据条件查询记录 <h3>
     * @author: Enzo
     * @date: 2019-1-15 1:11
     * @params [ms]
     * @return java.lang.String
     **/
    public String findByWhere(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        this.setResultType(ms, entityClass);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, this.tableName(entityClass)));
        Iterator columnList = EntityHelper.getColumns(entityClass).iterator();
        while (columnList.hasNext()) {
            EntityColumn column = (EntityColumn) columnList.next();
            if (ConstantsKey.Field.DELETED.equals(column.getProperty())) {
                sql.append("<where> AND " + column.getColumn() + "=0</where>");
                break;
            }
        }
        if (sql.indexOf("<where>") > -1) {
            sql.append("<if test=\"where!=null and where !=''\"> AND  ${where} </if>");
        } else {
            sql.append("<if test=\"where!=null and where !=''\"><where> AND  ${where} </where></if>");
        }

        sql.append(SqlHelper.orderByDefault(entityClass));
        return sql.toString();
    }

    /***
     * @title:<h3> 查询参数查询 <h3>
     * @author: Enzo
     * @date: 2019-1-15 1:50
     * @params [ms]
     * @return java.lang.String
     **/
    public String findByQueryParams(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        this.setResultType(ms, entityClass);
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT ${field} ");
//        sql.append("<if test=\"tableName==null\">");
        sql.append(SqlHelper.fromTable(entityClass, this.tableName(entityClass)));
        sql.append("<if test=\"join!=null and join !=''\"> ${join} </if>");
//        sql.append("</if>");
//        sql.append("<if test=\"tableName!=null\"> FROM  ${tableName} </if>");
        Iterator columnList = EntityHelper.getColumns(entityClass).iterator();
        while (columnList.hasNext()) {
            EntityColumn column = (EntityColumn) columnList.next();
            if (ConstantsKey.Field.DELETED.equals(column.getProperty())) {
                sql.append("<where> AND " + column.getColumn() + "=0</where>");
                break;
            }
        }
        if (sql.indexOf("<where>") > -1) {
            sql.append("<if test=\"where!=null and where !=''\"> AND  ${where} </if>");
        } else {
            sql.append("<if test=\"where!=null and where !=''\"><where> AND  ${where} </where></if>");
        }
        String defauleOrder=SqlHelper.orderByDefault(entityClass);
        sql.append(defauleOrder);
       if(defauleOrder.indexOf(" ORDER BY ")==-1){
           sql.append("<if test=\"order != null and order!='' \"> ORDER BY ${order}</if>");
           sql.append("<if test=\"defaultOrder != null and order!='' \">  ,${defaultOrder}</if>");
           sql.append("<if test=\"defaultOrder != null and order==''\">  ORDER BY ${defaultOrder}</if>");
       }else{
           sql.append("<if test=\"order != '' \"> ,${order}</if>");
           sql.append("<if test=\"defaultOrder != null \"> ,${defaultOrder}</if>");
       }


        return sql.toString();
    }
/***
 * @title:<h3> 设置更新字段 <h3>
 * @author: Enzo
 * @date: 2019-1-16 18:04
 * @params [entityClass, entityName, notNull, notEmpty]
 * @return java.lang.String
 **/
    public static String updateSetColumns(Class<?> entityClass, String entityName, boolean notNull, boolean notEmpty) {
        StringBuilder sql = new StringBuilder();
        sql.append("<set>");
        Set<EntityColumn> columnSet = EntityHelper.getColumns(entityClass);
        EntityColumn versionColumn = null;
        Iterator var7 = columnSet.iterator();

        while(true) {
            while(var7.hasNext()) {
                EntityColumn column = (EntityColumn)var7.next();
                if (column.getEntityField().isAnnotationPresent(Version.class)) {
                    if (versionColumn != null) {
                        throw new VersionException(entityClass.getCanonicalName() + " 中包含多个带有 @Version 注解的字段，一个类中只能存在一个带有 @Version 注解的字段!");
                    }

                    versionColumn = column;
                }

                if (!column.isId() && column.isUpdatable()) {
                    if (column == versionColumn) {
                        Version version = (Version)versionColumn.getEntityField().getAnnotation(Version.class);
                        String versionClass = version.nextVersion().getCanonicalName();
                        sql.append(column.getColumn()).append(" = ${@tk.mybatis.mapper.version.VersionUtil@nextVersion(").append("@").append(versionClass).append("@class, ").append(column.getProperty()).append(")},");
                    } else if (notNull) {
                        sql.append(SqlHelper.getIfNotNull(entityName, column, column.getColumnEqualsHolder(entityName) + ",", notEmpty));
                    } else {
                        sql.append(column.getColumnEqualsHolder(entityName) + ",");
                    }
                } else if (!column.isId() && column.isUpdatable()) {
                    sql.append(column.getColumn()).append(" = ").append(column.getColumn()).append(",");
                }
            }

            sql.append("</set>");
            return sql.toString();
        }
    }
    /***
     * @title:<h3> 根据条件查询记录数 <h3>
     * @author: Enzo
     * @date: 2019-1-15 1:11
     * @params [ms]
     * @return java.lang.String
     **/
    public String countByWhere(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectCount(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, this.tableName(entityClass)));
        Iterator columnList = EntityHelper.getColumns(entityClass).iterator();
        while (columnList.hasNext()) {
            EntityColumn column = (EntityColumn) columnList.next();
            if (ConstantsKey.Field.DELETED.equals(column.getProperty())) {
                sql.append("<where> AND " + column.getColumn() + "=0</where>");
                break;
            }
        }
        if (sql.indexOf("<where>") > -1) {
            sql.append("<if test=\"where!=null and where !=''\"> AND  ${where} </if>");
        } else {
            sql.append("<if test=\"where!=null and where !=''\"><where> AND  ${where} </where></if>");
        }
        return sql.toString();
    }
    /**
    * <h3>条件更新，忽略主键</h3>
    * @params [ms]
    * @author Enzo
    * @date 2019-3-25  15:41
    * @return java.lang.String
    */
    public String updateByExampleService(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        if (this.isCheckExampleEntityClass()) {
            sql.append(SqlHelper.exampleCheck(entityClass));
        }

        if (this.getConfig().isSafeUpdate()) {
            sql.append(SqlHelper.exampleHasAtLeastOneCriteriaCheck("example"));
        }

        sql.append(SqlHelper.updateTable(entityClass, this.tableName(entityClass), "example"));
        sql.append(updateSetColumns(entityClass, "record", true, this.isNotEmpty()));
        sql.append(SqlHelper.updateByExampleWhereClause());
        return sql.toString();
    }
}
